package org.simpleframework.core;

import com.sun.corba.se.spi.activation.Server;
import javafx.util.BuilderFactory;
import org.simpleframework.annotation.*;
import org.simpleframework.util.ClassUtil;
import org.simpleframework.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author
 * @date 2022/10/4 16:38
 **/
public class AnnotationConfigApplicationContext {


    /**
     * class类池 Object 为实例对象
     */
    private Map<Class<?>, Object> classMap = new ConcurrentHashMap<>();


    /**
     * 单例池
     */
    private Map<String, Object> singletonMap = new ConcurrentHashMap<>();
    /**
     * 存储注解
     */
    private List<Class<? extends Annotation>> annotationLsit = Arrays.asList(Component.class
            , Controller.class, Repository.class, Service.class);
    /**
     * 扫描包获取到的class
     */
    private Set<Class<?>> classSet;
    /**
     * 配置类
     */
    private Class<?> classConfig;

    public AnnotationConfigApplicationContext() {

    }

    public AnnotationConfigApplicationContext(Class<?> classConfig) {
        this.classConfig = classConfig;
        register(classConfig); // TODO 获取配置类的信息
        refresh();  // 刷新容器
    }

    /**
     * 注册class
     *
     * @param classConfig
     */
    private void register(Class<?> classConfig) {
        this.classSet = ClassUtil.extractPackageClass("com.it");
    }

    public Object getBean(String name) {
        return singletonMap.get(name);
    }

    /**
     * 刷新容器
     */
    private void refresh() {
        Set<Class<?>> classSet = this.classSet;
        for (Class<?> clazz : classSet) { // 遍历获取到class文件， 检查是否有对应的注解
            if (clazz.isAnnotationPresent(Component.class)) {
                Object instance = ClassUtil.getInstance(clazz, true);
                Component component = clazz.getAnnotation(Component.class);
                String commponentValue = component.value(); // 获取注解上的值
                if (ValidationUtil.isEmpty(commponentValue)) { // 如果为空的话就使用驼峰命名法
                    String name = clazz.getName();
                    // 默认
                    name = name.substring(name.lastIndexOf(".") + 1);
                    // 首字母小写
                    name = name.substring(0, 1).toLowerCase() + name.substring(1);
                    singletonMap.put(name, instance);
                    classMap.put(clazz, instance);
                } else {  // 如果有指定beanName
                    singletonMap.put(commponentValue, instance);
                    classMap.put(clazz, instance);
                }
            } else if (clazz.isAnnotationPresent(Service.class)) {
                Object instance = ClassUtil.getInstance(clazz, true);
                Service service = clazz.getAnnotation(Service.class);
                String serviceValue = service.value(); // 获取注解上的值
                if (ValidationUtil.isEmpty(serviceValue)) { // 如果为空的话就使用驼峰命名法
                    String name = clazz.getName();
                    // 默认
                    name = name.substring(name.lastIndexOf(".") + 1); // 从最后一个点开始截取再减一\
                    // 首字母小写
                    name = name.substring(0, 1).toLowerCase() + name.substring(1);
                    singletonMap.put(name, instance);
                    classMap.put(clazz, instance);
                } else {  // 如果有指定beanName
                    singletonMap.put(serviceValue, instance);
                    classMap.put(clazz, instance);
                }
            } else if (clazz.isAnnotationPresent(Repository.class)) {
                Object instance = ClassUtil.getInstance(clazz, true);
                Repository repository = clazz.getAnnotation(Repository.class);
                String repositoryValue = repository.value(); // 获取注解上的值
                if (ValidationUtil.isEmpty(repositoryValue)) { // 如果为空的话就使用驼峰命名法
                    String name = clazz.getName();
                    // 默认
                    name = name.substring(name.lastIndexOf(".") + 1); // 从最后一个点开始截取再减一
                    // 首字母小写
                    name = name.substring(0, 1).toLowerCase() + name.substring(1);
                    singletonMap.put(name, instance);
                    classMap.put(clazz, instance);
                } else {  // 如果有指定beanName
                    singletonMap.put(repositoryValue, instance);
                    classMap.put(clazz, instance);

                }
            } else if (clazz.isAnnotationPresent(Controller.class)) {
                Object instance = ClassUtil.getInstance(clazz, true);

                Controller controller = clazz.getAnnotation(Controller.class);
                String controllerValue = controller.value(); // 获取注解上的值
                if (ValidationUtil.isEmpty(controllerValue)) { // 如果为空的话就使用驼峰命名法
                    String name = clazz.getName();
                    // 默认
                    name = name.substring(name.lastIndexOf(".") + 1); // 从最后一个点开始截取再减一
                    // 首字母小写
                    name = name.substring(0, 1).toLowerCase() + name.substring(1);

                    singletonMap.put(name, instance);
                    classMap.put(clazz, instance);

                } else {  // 如果有指定beanName
                    singletonMap.put(controllerValue, instance);
                    classMap.put(clazz, instance);
                }
            }

        }
        // 实例化所有对象 over
//        TODO 依赖注入
        injectDependcy();
//             依赖注入over
    }

    /**
     * 依赖注入 使用autowired 进行依赖注入
     * 先类型后名字
     */
    private void injectDependcy() {
        Map<Class<?>, Object> classMap = this.classMap;
        Set<Class<?>> classSet = classMap.keySet();
        for (Class<?> aClass : classSet) {
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    Autowired autowired = (Autowired) field.getAnnotation(Autowired.class);
                    String autowiredValue = autowired.value();
                    // autowired注解的值为空的话，就默认采用驼峰命名法
                    if (ValidationUtil.isEmpty(autowiredValue)) {
                        Class<?> fieldClass = field.getType();
//                         查询字段的实例
//                         到这查询字段的实例，并且autowired的值为空
                        Object instance = getFieldInstance(fieldClass, autowiredValue);
                        ClassUtil.setField(field, classMap.get(aClass),
                                instance, true);
                    } else { // 如果注解值不为空
//                        内部会进行判断，根据注解的值匹配实例
                        Class<?> fieldClass = field.getType();
                        Object instance = getFieldInstance(fieldClass, autowiredValue);
                        ClassUtil.setField(field, classMap.get(aClass),
                                instance, true);

                    }
                }
            }
        }
//         start DI


    }

    /**
     * @param fieldClass     字段的类型
     * @param autowiredValue 注解值
     * @return
     */
    private Object getFieldInstance(Class<?> fieldClass, String autowiredValue) {
//               1. 先根据fieldClass 查找，看看能不能直接找到
        // 2. 如果找到了说明类型可能就是实现类 而不是接口
        Object instance = classMap.get(fieldClass);
        if (instance != null) {
            return instance;
        } else { // 可能类型是接口 或者根本就没有这个实例
            // 去找实现类
            Class<?> clazz = getImplClass(fieldClass, autowiredValue);
//            到这 找到实现类
            instance = classMap.get(clazz);
            return instance;
        }

        // 到这，还是没找到实例的话就抛出异常
    }

    /**
     * 根据 字段的class查找对应的实现类
     *
     * @param fieldClass
     * @param autowiredValue
     * @return
     */
    private Class<?> getImplClass(Class<?> fieldClass, String autowiredValue) {
        // 根据接口class查询实现的class
        Set<Class<?>> classSet = getClassBySuper(fieldClass);
        if (ValidationUtil.isEmpty(classSet)) {
            throw new RuntimeException("注入失败，找不到实例");
        }
        if (classSet.size() == 1) {
            // 如果就只找到一个实现类就直接返回
            return classSet.iterator().next();
        } else { // 到这里有多个实现类
            for (Class<?> clazz : classSet) {
                String name = clazz.getName();
                // 得到实例名
                name = name.substring(name.lastIndexOf(".") + 1);
                name = name.substring(0, 1).toLowerCase() + name.substring(1);
                // 到这，已经是有多个实现类了，如果还没指定名字就抛出异常
                if (ValidationUtil.isEmpty(autowiredValue)) {
                    throw new RuntimeException("有多个实现类,请通过autowired指定名字");
                }
                // 如果有指定名字就根据名字进行查询
                if (autowiredValue.equals(name)) {
                    return clazz;
                }
            }
        }
        // 到这里说明，有多个实现类，名字也指定了，但是都没找到，抛异常咯
        throw new RuntimeException("sorry，指定名字也没找到");
    }

    /**
     * 根据父类型class查找及其实现类class
     *
     * @param fieldClass
     * @return
     */
    private Set<Class<?>> getClassBySuper(Class<?> fieldClass) {
        Set<Class<?>> classSet = classMap.keySet();
        Set<Class<?>> collectionSet = new HashSet<>();
        for (Class<?> clazz : classSet) {
            // 找到子类型
            if (fieldClass.isAssignableFrom(clazz)) {
                collectionSet.add(clazz);
            }
        }
        return collectionSet.size() > 0 ? collectionSet : null;
    }


    public String[] getBeanDefinitionNames() {
        Set<String> keySet = singletonMap.keySet();
        String[] strings = keySet.toArray(new String[keySet.size()]);
        return strings;

    }
}
